package com.rybbaby.tss.platform.sysFiles.service.imp;

import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.model.DefaultPutRet;
import com.rybbaby.tss.core.bean.TempUploadFile;
import com.rybbaby.tss.core.utils.*;
import com.rybbaby.tss.core.utils.pojo.TreeFile;
import com.rybbaby.tss.core.web.service.imp.BaseServiceImp;
import com.rybbaby.tss.platform.sysFileDistributedHistory.entity.SysFileDistributedHistory;
import com.rybbaby.tss.platform.sysFileDistributedHistory.service.ISysFileDistributedHistoryService;
import com.rybbaby.tss.platform.sysFileServer.entity.SysFileServer;
import com.rybbaby.tss.platform.sysFileServer.service.ISysFileServerService;
import com.rybbaby.tss.platform.sysFileUseLog.entity.SysFileUseLog;
import com.rybbaby.tss.platform.sysFileUseLog.service.ISysFileUseLogService;
import com.rybbaby.tss.platform.sysFiles.entity.SysFiles;
import com.rybbaby.tss.platform.sysFiles.service.ISysFilesService;
import org.apache.commons.lang.StringEscapeUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author 谢进伟
 * @description 文件库数据库操作服务实现
 * @createDate 2016-11-12 上午10:03:27
 */
@Service
@Transactional
public class SysFilesServiceImp extends BaseServiceImp<SysFiles> implements ISysFilesService {

    @Autowired
    private ISysFileServerService sysFileServerService;
    @Autowired
    private ISysFileDistributedHistoryService sysFileDistributedHistoryService;
    @Autowired
    private ISysFileUseLogService sysFileUseLogService;
    /**
     * 文件本地缓存目录
     **/
    private static String localCacheFileDir = "E:/localCache/";

    static {
        // 读取资源值
        localCacheFileDir = PropertiesReadUtil.getStringProperty("SysFilesServiceImp.localCacheFileDir", localCacheFileDir);
    }

    @Override
    public List<Map<String, Object>> groupIdDatasource() {
        String sql11 = "SELECT id,name FROM sys_file_group";
        List<Map<String, Object>> groupId_datasources = this.findForJdbc(sql11, null);
        return groupId_datasources;
    }

    @Override
    public boolean useFile(String businessTableName, String primaryKeyFieldName, Serializable businessId, String fieldName, String cacheGroupNames, String sessionId, String loginUserId, String oldValue) throws Exception {
        return this.useFile(businessTableName, primaryKeyFieldName, businessId, fieldName, cacheGroupNames, sessionId, loginUserId, oldValue, false);
    }

    public boolean useFile(String businessTableName, String primaryKeyFieldName, Serializable businessId, String fieldName, String cacheGroupNames, String sessionId, String loginUserId, String oldValue, boolean isUpdate) throws Exception {
        if (StringUtils.isBlank(fieldName) || StringUtils.isBlank(cacheGroupNames) || StringUtils.isBlank(businessId)) {
            return false;
        }
        List<String> usedFileIds = new ArrayList<String>();
        for (String groupName : cacheGroupNames.split(",")) {
            TempUploadFile tempUploadFile = FileUploadUtil.getTempUploadFile(groupName, sessionId);
            if (tempUploadFile == null) {
                if (!isUpdate) {
                    throw new Exception("没有上传任何文件或缓存文件丢失!");
                } else {
                    continue;
                }
            }
            List<TreeFile> fileList = tempUploadFile.getFileList();
            for (TreeFile tf : fileList) {
                File cacheFile = new File(tf.getPath());
                // 原始文件名
                String originalFileName = tf.getName();
                //后缀
                String suffix = StringUtils.substringAfterLast(originalFileName, ".");
                String parentFilePath = cacheFile.getParentFile().getPath();
                //重命名文件
                String fileName = SequenceUtil.getLowerCaseUUID();
                boolean rename = FileUtils.rename(cacheFile, fileName);
                if (rename) {
                    fileName = fileName + "." + suffix;
                    cacheFile = new File(parentFilePath + "/" + fileName);
                }
                if (!cacheFile.exists()) {
                    throw new Exception("缓存文件丢失!");
                }

                SimpleDateFormat sdf = new SimpleDateFormat("yyyy" + File.separator + "MM" + File.separator + "dd" + File.separator + "HH");
                String relativePath = cacheGroupNames + File.separator + sdf.format(new Date());
                Timestamp currentTime = new Timestamp(System.currentTimeMillis());
                // 保存文件
                SysFiles sf = new SysFiles();
                sf.setOriginalFileName(originalFileName);
                sf.setFileName(fileName);
                sf.setType(FileUtils.getFileType(cacheFile));
                sf.setUploadTime(currentTime);
                sf.setRelativePath(relativePath.replaceAll("\\|\\\\", "/"));
                sf.setUserId(loginUserId == null ? null : loginUserId);
                if (StringUtils.isNotBlank(originalFileName)) {
                    sf.setType(suffix);
                }
                Serializable fileId = save(sf);
                // 本地缓存
                File localCacheFileDirFile = new File(localCacheFileDir + File.separator + relativePath);
                if (!localCacheFileDirFile.exists()) {
                    boolean mkdirs = localCacheFileDirFile.mkdirs();
                    if (!mkdirs) {
                        throw new Exception("本地缓文件存目录创建失败!");
                    }
                }
                File localCacheFile = new File(localCacheFileDirFile.getPath() + File.separator + fileName);
                FileUtils.copyFile(cacheFile, localCacheFile);
                //上传到七牛云存储
                QiNiuUtil.upload(localCacheFile, new QiNiuUtil.QiNiuUploadCallback() {
                    @Override
                    public void execute(Object retObj) {
                        if (retObj instanceof DefaultPutRet) {
                            DefaultPutRet ret = (DefaultPutRet) retObj;
                            if (ret != null) {
                                String key = ret.key;
                                String hash = ret.hash;
                                String sql = "UPDATE sys_files SET qiniuHash=?,qiniuKey=? WHERE id=?";
                                Integer integer = executeSql(sql, new Object[]{hash, key, fileId});
                                if (integer > 0) {
                                    info("文件：" + fileId + "成功同步到七牛云存储!");
                                } else {
                                    info("上传七牛云存储失败!");
                                }
                            } else {
                                info("上传七牛云存储失败!");
                            }
                        }
                    }
                });
                // 文件分发
                if (fileId != null) {
                    usedFileIds.add(fileId.toString());
                    DetachedCriteria dc = DetachedCriteria.forClass(SysFileServer.class);
                    dc.add(Restrictions.eq("status", 1));// 已启用的文件服务器
                    List<SysFileServer> serverIndexList = this.sysFileServerService.findByDetached(dc);
                    // 文件分发记录
                    SysFileDistributedHistory sfdh = new SysFileDistributedHistory();
                    sfdh.setStatus(1);
                    sfdh.setFileId(fileId.toString());
                    sfdh.setCreateTime(currentTime);
                    sfdh.setLastDistributedTime(currentTime);
                    // 判断是否配置文件服务器
                    if (serverIndexList == null || serverIndexList.isEmpty()) {
                        sfdh.setStatus(0);// 未分发
                        Serializable sfdhsId = SysFilesServiceImp.this.sysFileDistributedHistoryService.save(sfdh);
                        if (sfdhsId != null) {
                            info("保存分发记录：" + sfdhsId + "成功!");
                        } else {
                            info("保存分发记录：" + sfdhsId + "失败!");
                        }
                    } else {
                        // 分发文件到文件服务器
                        for (SysFileServer fileServer : serverIndexList) {
                            sfdh.setFileServerId(fileServer.getId());
                            String ip = fileServer.getIp();
                            String host = fileServer.getFtpHost();
                            String loginName = fileServer.getFtpLoginName();
                            String password = fileServer.getFtpPassword();
                            String rootDir = fileServer.getRootDir();
                            String uploadUrl = fileServer.getUploadUrl();
                            String remark = fileServer.getRemark();
                            // 默认使用ftp分发
                            FileUploadUtil.ftpDistributedFile(ip, host, loginName, password, rootDir, relativePath, localCacheFile, (Boolean status) -> {
                                // 尝试使用http方式分发
                                String name = localCacheFile.getName();
                                if (!status && StringUtils.isNotBlank(uploadUrl)) {
                                    FileUploadUtil.httpDistributedFile(uploadUrl, rootDir, relativePath, localCacheFile, (Boolean status1) -> {
                                        if (!status1) {
                                            String message = "文件" + name + " 在分发到文件服务器：" + ip + "(" + remark + "失败!)";
                                            error(message);
                                        } else {
                                            debug("文件" + name + " 成功分发到服务器：" + ip + "(" + remark + ")");
                                        }
                                        sfdh.setStatus(status1 ? 1 : 2);
                                        Serializable sfdhsId = SysFilesServiceImp.this.sysFileDistributedHistoryService.save(sfdh);
                                        if (sfdhsId != null) {
                                            info("保存分发记录：" + sfdhsId + "成功!");
                                        } else {
                                            info("保存分发记录：" + sfdhsId + "失败!");
                                        }
                                    });
                                } else {
                                    sfdh.setStatus(1);
                                    Serializable sfdhsId = SysFilesServiceImp.this.sysFileDistributedHistoryService.save(sfdh);
                                    if (sfdhsId != null) {
                                        info("保存分发记录：" + sfdhsId + "成功!");
                                    } else {
                                        info("保存分发记录：" + sfdhsId + "失败!");
                                    }
                                    debug("文件" + name + " 成功分发到服务器：" + ip + "(" + remark + ")");
                                }
                            });
                        }
                    }
                }
                // 文件使用记录
                SysFileUseLog sfu = new SysFileUseLog();
                sfu.setFileId(fileId.toString());
                sfu.setBusinessTableName(businessTableName);
                sfu.setBusinessId(businessId.toString());
                sfu.setCreateTime(currentTime);
                sfu.setSize(tf.getSize().toString());
                sfu.setBusinessField(fieldName);
                Serializable sfuId = sysFileUseLogService.save(sfu);
                if (sfuId != null) {
                    info("保存使用记录：" + sfuId + "成功!");
                } else {
                    info("保存使用记录：" + sfuId + "失败!");
                }
            }
        }
        if (!usedFileIds.isEmpty()) {
            if (StringUtils.isNotBlank(oldValue)) {
                usedFileIds.addAll(Arrays.asList(oldValue.split(",")));
            }
            String sql = "UPDATE " + StringEscapeUtils.escapeSql(businessTableName) + " SET " + StringEscapeUtils.escapeSql(StringEscapeUtils.escapeSql(fieldName)) + "='" + StringEscapeUtils.escapeSql(StringUtils.join(usedFileIds, ",")) + "' WHERE " + StringEscapeUtils.escapeSql(primaryKeyFieldName) + "=?";
            return this.executeSql(sql, new Object[]{businessId}) > 0;
        }
        return true;
    }

    @Override
    public boolean updateUsedFile(String businessTableName, String primaryKeyFieldName, Serializable businessId, String fieldName, String cacheGroupNames, String sessionId, String loginUserId, String delteFileIds, String oldValue) throws Exception {
        if (StringUtils.isNotBlank(delteFileIds)) {
            if (delteFileIds.startsWith(",")) {
                delteFileIds = StringUtils.substringAfter(delteFileIds, ",");
            }
            if (delteFileIds.endsWith(",")) {
                delteFileIds = StringUtils.substringBeforeLast(delteFileIds, ",");
            }
            String sql = "SELECT fileName,relativePath FROM sys_files WHERE id IN(SELECT fileId FROM sys_file_use_log WHERE businessId=? AND businessField=?) AND id IN('" + StringUtils.join(delteFileIds.split(","), "','") + "')";
            List<SysFiles> existsFile = findListBySql(sql, new Object[]{businessId, fieldName});
            // 删除文件,同时数据库设置级联删除文件分发记录和使用记录
            sql = "SELECT qiniuKey FROM sys_files WHERE id IN('" + StringEscapeUtils.escapeSql(delteFileIds) + "') ";
            List<Map<String, Object>> deleteKeyList = findForJdbc(sql, null);
            sql = "DELETE FROM sys_files WHERE id IN('" + StringUtils.join(delteFileIds.split(","), "','") + "') ";
            if (this.executeSql(sql, new Object[]{}) > 0) {
                info("已删除历史文件分发记录!");
                // 删除本地缓存文件
                File localCacheFileDirFile = new File(localCacheFileDir);
                if (localCacheFileDirFile.exists()) {
                    for (SysFiles file : existsFile) {
                        File f = new File(localCacheFileDirFile.getPath() + File.separator + file.getRelativePath() + File.separator + file.getFileName());
                        if (f.exists()) {
                            boolean delete = f.delete();
                            if (!delete) {
                                f.deleteOnExit();
                            }
                        }
                    }
                }
                // 删除七牛云存储文件
                if (deleteKeyList != null && !deleteKeyList.isEmpty()) {
                    deleteKeyList.forEach((Map<String, Object> keyMap) -> {
                        if (keyMap != null && keyMap.containsKey("qiniuKey")) {
                            Object key = keyMap.get("qiniuKey");
                            QiNiuUtil.delete(key.toString(), new QiNiuUtil.QiNiuDeleteFileCallback() {
                                @Override
                                public void execute(Object responseObj) {
                                    if (responseObj instanceof Response) {
                                        Response response = (Response) responseObj;
                                        boolean ok = response.isOK();
                                        if (ok) {
                                            log.info("七牛云存储：" + key + " 删除成功!");
                                        } else {
                                            log.info("七牛云存储：" + key + "删除失败!");
                                        }
                                        try {
                                            log.info("删除操作响应体：");
                                            log.info(response.bodyString());
                                        } catch (QiniuException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            });
                        }
                    });
                }
                // TODO 删除文件服务器文件
                // ...
            }
        }
        return useFile(businessTableName, primaryKeyFieldName, businessId, fieldName, cacheGroupNames, sessionId, loginUserId, oldValue, true);
    }

}
